package route

import (
	"bytes"
	"frozen-go-mini/common/mycontext"
	"frozen-go-mini/common/mylogrus"
	"frozen-go-mini/resp"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"github.com/spf13/cast"
	"io"
	"net/http"
	"strings"
	"time"
)

/**
controller层全局异常处理
*/

// 等级最高，为了只为最后有返回值到前端
func ExceptionHandle(c *gin.Context) {
	defer func() {
		if r := recover(); r != nil {
			//打印错误堆栈信息
			resp.ResponseErrWithString(c, r)
			//终止后续接口调用，不加的话recover到异常后，还会继续执行接口里后续代码
			c.Abort()
		}
	}()
	c.Next()
}

func genTraceId(c *gin.Context) string {
	if trace := c.GetHeader(mycontext.TRACEID); len(trace) > 0 {
		return trace
	}
	traceId := strings.Replace(uuid.NewV4().String(), "-", "", -1)
	traceId = traceId[:len(traceId)/2]
	return traceId
}

// LoggerHandle 日志Handle
func LoggerHandle(c *gin.Context) {
	//开始时间
	start := time.Now()
	clientIp := c.ClientIP()
	method := c.Request.Method
	traceId := genTraceId(c)
	reqUri := c.Request.RequestURI
	c.Set(mycontext.TRACEID, traceId)
	//
	header := c.Request.Header
	//类型
	devicetype := header.Get("Devicetype")
	c.Set(mycontext.DEVICETYPE, devicetype)
	appVersion := header.Get("Appversion")
	c.Set(mycontext.APP_VERSION, appVersion)
	c.Set(mycontext.URL, reqUri)
	c.Set(mycontext.METHOD, method)

	//userId, _ := req.GetUserId(c)
	userId := 0 // todo

	bodyStr := ""
	contentType := c.Request.Header.Get("Content-Type")

	//文件就不打印
	if strings.Index(contentType, "multipart/form-data") == -1 {
		data, err := c.GetRawData()
		if err != nil {
			mylogrus.MyLog.Errorf("handle log err:%v", err)
		}
		bodyStr = string(data)
		//很关键
		//把读过的字节流重新放到body
		c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
	}

	mycontext.CreateMyContext(c.Keys).Log.Infof("request start traceId:%v, clientIp:%v, url:%v, method:%v, userId:%v, body:%v, header:%v", traceId, clientIp, reqUri, method, userId, bodyStr, header)
	//加载完 defer recover，继续后续接口调用
	c.Next()
	end := time.Now()
	latency := end.Sub(start)
	mycontext.CreateMyContext(c.Keys).Log.Infof("request end fullPath:%v,url:%v, method: %v, traceId:%v, latency:%v userId:%v", c.FullPath(), reqUri, method, traceId, latency, userId)
}

// jwt解密
func JWTApiHandle(c *gin.Context) {
	userId := cast.ToUint64(c.GetHeader("userId"))
	if userId > 0 {
		c.Set(mycontext.USERID, userId)
	}
	c.Next()
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")
		if origin != "" {
			c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		c.Next()
	}
}
